package com.ych.modules.base.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.ych.SDK.alibaba.ossSDK.AliOssUtil;
import com.ych.modules.base.dbEntity.TUserAccountChangeEntity;
import com.ych.modules.base.dbEntity.TUserAccountEntity;
import com.ych.modules.base.dbEntity.TUserAccountRechargeOrderEntity;
import com.ych.modules.base.dbEntity.TUserInfoEntity;
import com.ych.modules.base.mapper.TUserInfoMapper;
import com.ych.modules.base.service.*;
import com.ych.modules.sql.service.ISysSqlService;
import com.ych.modules.sql.util.SqlBaseUtil;
import com.ych.redis.RedisLockUtil;
import com.ych.redis.config.RedisKeyConfig;
import com.ych.utils.TLMap;
import com.ych.utils.UUID;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * Author: Usopp.tsui
 * Date: 2020/12/5
 * Time: 15:10
 * Description:
 */
@Service("ITUserInfoService")
public class TUserInfoServiceImpl extends ServiceImpl<TUserInfoMapper, TUserInfoEntity> implements ITUserInfoService {
    @Autowired
    private IRUserInfoSysRoleService          irUserInfoSysRoleService;
    @Autowired
    private ITSysMenuService                  itSysMenuService;
    @Autowired
    private ITUserAccountService              itUserAccountService;
    @Autowired
    private ITUserAccountRechargeOrderService itUserAccountRechargeOrderService;
    @Autowired
    private ITUserAccountChangeService        itUserAccountChangeService;
    @Autowired
    private ISysSqlService                    iSysSqlService;
    @Autowired
    private AliOssUtil                        aliOssUtil;

    @Override
    public TUserInfoEntity queryByUserId(String userId) {
        TUserInfoEntity userInfoEntity = this.selectById(userId);
        //可以再加入其他的用户相关查询
        if (null != userInfoEntity) {
            userInfoEntity = this.extendsUserInfo(userInfoEntity);
            userInfoEntity.setUserHeadUrl(aliOssUtil.getOssObjectDownAuthUrl(userInfoEntity.getUserHeadUrl()));
            //查询推荐人信息
            TUserInfoEntity inviterEntity = this.selectById(userInfoEntity.getRecommenderUserId());
            TUserInfoEntity tempEntity = new TUserInfoEntity();
            tempEntity.setMobile(inviterEntity.getMobile());
            tempEntity.setUserName(inviterEntity.getUserName());
            tempEntity.setUserHeadUrl(aliOssUtil.getOssObjectDownAuthUrl(inviterEntity.getUserHeadUrl()));
            userInfoEntity.setInviterEntity(tempEntity);
        }
        return userInfoEntity;
    }

    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void save(TUserInfoEntity user) {
        this.createInvitation(user);
        //sha256加密
        String salt = RandomStringUtils.randomAlphanumeric(20);
        user.setPassword(new Sha256Hash(user.getPassword(), salt).toHex());
        user.setSalt(salt);
        user.setStatus("0");
        user.setUserId(UUID.randomUUID());
        user.setCreateUserId("1");
        user.setCreateTime(new Date());
        if (StringUtils.isBlank(TLMap.getUserId())) {
            user.setCreateUserId("1");
        } else {
            user.setCreateUserId(TLMap.getUserId());
        }
        user.setUserName("用户" + user.getMobile().substring(7));
        //根据邀请码查询推荐者
        Wrapper<TUserInfoEntity> wrapper = new EntityWrapper<TUserInfoEntity>()
                .where("1=1")
                .eq("invitation", user.getRecommenderInvitation());
        TUserInfoEntity recommenderEntity = this.selectOne(wrapper);
        if (null == recommenderEntity) {
            throw new RuntimeException("未查询到推荐人信息");
        }
        if (!"0".equals(recommenderEntity.getStatus())) {
            throw new RuntimeException("当前邀请码已禁止使用");
        }
        //推荐者主键
        user.setRecommenderUserId(recommenderEntity.getUserId());
        //获取推荐者的所有父节点
        String introducerPids = recommenderEntity.getPids();
        user.setPids("'" + recommenderEntity.getUserId() + "'," + this.pidsIsRight(introducerPids));
        //user_id为1，则为admin根用户
        if ("1".equals(recommenderEntity.getUserId())) {
            user.setPids("'" + recommenderEntity.getUserId() + "'");
        }
        //新增用户
        this.insert(user);
        //创建用户账户
        this.addUserAccount(user);
        //添加优惠券记录（充值订单+变更记录）
        String rechargeId = this.addRaffleTickets(user, 1, "10002004", null);//注册赠送
        //添加推荐人优惠券记录
        TUserInfoEntity parentUserInfo = this.selectById(recommenderEntity.getUserId());
        this.addRaffleTickets(parentUserInfo, 1, "10002005", rechargeId);//下级注册赠送
        //检查角色是否越权
        this.checkRole(user);
        //保存用户与角色关系
        irUserInfoSysRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList());
        //更新所有父级下线人数（开启单独的线程处理）
        this.updatePid(user);
    }

    @Override
    public List<String> queryAllMenuId(String userId) {
        String sql = "select distinct rm.menu_id AS var1 from r_user_info_sys_role ur " +
                "LEFT JOIN r_sys_role_menu rm on ur.role_id = rm.role_id " +
                "where ur.user_id = '" + userId + "'";
        List<Map<String, Object>> listMap = iSysSqlService.selectSql(sql);
        return SqlBaseUtil.SqlReturnListObj(listMap, null);
    }

    /**
     * 进行分发抽奖券
     *
     * @param userId
     */
    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void rewardRaffleTicket(String userId) {
        try {
            TUserInfoEntity userInfoEntity = this.selectById(userId);
            //获取注册时赠送抽奖券的订单号
            String rechargeId = this.findRegisterOrderId(userId);
            //查询父节点集合
            List<TUserInfoEntity> list = this.listPidsEntities(userInfoEntity);
            for (TUserInfoEntity entity : list) {
                //直推不赠送
//            if (userInfoEntity.getRecommenderUserId().equals(entity.getUserId())) {
//                continue;
//            }
                //赠送父级优惠券（默认情况下直推不赠送）
                TUserInfoEntity infoEntity = this.selectById(entity.getRecommenderUserId());
                if (null == infoEntity) {
                    continue;
                }
                //判断父级是否赠送优惠券
                boolean isTicket = this.validateIsTicket(entity, infoEntity);
                if (isTicket) {
                    //赠送父级抽奖券
                    this.addRaffleTickets(infoEntity, 1, "10002005", rechargeId);//下级注册赠送
                }
            }
            TUserInfoEntity tempEntity = new TUserInfoEntity();
            tempEntity.setUserId(userInfoEntity.getUserId());
            //分发完了  修改用户分发状态为已分发
            tempEntity.setIsTicket("0");
            this.updateById(tempEntity);
        } catch (Exception e) {
            e.printStackTrace();
            throw e;
        }
    }

    @Override
    @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void update(TUserInfoEntity tUserInfo) {
        TUserInfoEntity selectEntity = this.selectById(tUserInfo.getUserId());
        tUserInfo.setCreateUserId(selectEntity.getCreateUserId());
        if (StringUtils.isBlank(tUserInfo.getPassword())) {
            tUserInfo.setPassword(null);
        } else {
            tUserInfo.setPassword(new Sha256Hash(tUserInfo.getPassword(), selectEntity.getSalt()).toHex());
        }
        this.updateById(tUserInfo);
        //检查角色是否越权
        checkRole(tUserInfo);
        //保存用户与角色关系
        irUserInfoSysRoleService.saveOrUpdate(tUserInfo.getUserId(), tUserInfo.getRoleIdList());
    }

    @Override
    public void validatePayPassword(String userId, String password) {
        TUserInfoEntity userInfoEntity = this.selectById(userId);
        if (null == userInfoEntity) {
            throw new RuntimeException("用户不存在");
        }
        if (StringUtils.isBlank(userInfoEntity.getPayPassword())) {
            throw new RuntimeException("支付密码未设置");
        }
        String salt = userInfoEntity.getSalt();
        password = new Sha256Hash(password, salt).toHex();
        if (!password.equals(userInfoEntity.getPayPassword())) {
            throw new RuntimeException("密码错误!");
        }
    }

    /**
     * 判断父级是否赠送优惠券
     *
     * @param entity
     * @return
     */
    private boolean validateIsTicket(TUserInfoEntity entity, TUserInfoEntity parentEntity) {
        if (entity.getUserId().equals(parentEntity.getMaxSubordinateUserId())
                || entity.getUserId().equals(parentEntity.getSecondSubordinateUserId())) {
            return false;
        }
        return true;
    }

    /**
     * 获取注册时赠送抽奖券的订单号
     *
     * @param userId
     * @return
     */
    private String findRegisterOrderId(String userId) {
        Wrapper<TUserAccountRechargeOrderEntity> wrapper = new EntityWrapper<TUserAccountRechargeOrderEntity>()
                .where("1=1")
                .eq("user_id", userId)
                .eq("recharge_channel", "10002004");
        TUserAccountRechargeOrderEntity orderEntity = itUserAccountRechargeOrderService.selectOne(wrapper);
        if (null == orderEntity) {
            throw new RuntimeException("注册订单不存在！");
        }
        return orderEntity.getRechargeId();
    }

    /**
     * 创建用户账户
     *
     * @param user
     */
    private void addUserAccount(TUserInfoEntity user) {
        TUserAccountEntity tUserAccountEntity = new TUserAccountEntity();
        tUserAccountEntity.setUserId(user.getUserId());
        itUserAccountService.insert(tUserAccountEntity);
    }

    /**
     * 添加优惠券记录（充值订单+变更记录）
     *
     * @param user                添加用户
     * @param ticketNum           优惠券数量
     * @param rechargeChannelType 订单类型
     * @param paymentOrderId      支付订单id。如订单类型为下级注册赠送，则该订单号为注册赠送的订单的订单号
     * @return
     */
    private String addRaffleTickets(TUserInfoEntity user, Integer ticketNum, String rechargeChannelType, String paymentOrderId) {
        TUserAccountEntity accountEntity = itUserAccountService.selectById(user.getUserId());
        String rechargeId = UUID.randomUUID();
        //添加充值订单
        TUserAccountRechargeOrderEntity rechargeOrderEntity = new TUserAccountRechargeOrderEntity();
        rechargeOrderEntity.setRechargeId(rechargeId);
        rechargeOrderEntity.setUserId(user.getUserId());
        rechargeOrderEntity.setRechargeChannel(rechargeChannelType);//管理员充值
        rechargeOrderEntity.setRechargeStatus("10003002");//交易成功
        rechargeOrderEntity.setCashAmount(BigDecimal.ZERO);
        rechargeOrderEntity.setVip(0);
        rechargeOrderEntity.setRaffleTicket(ticketNum);
        rechargeOrderEntity.setCreateTime(new Date());
        rechargeOrderEntity.setCollectionAccount("-1");
        rechargeOrderEntity.setPaymentOrderId(paymentOrderId);
        itUserAccountRechargeOrderService.insert(rechargeOrderEntity);
        //添加变更记录
        TUserAccountChangeEntity changeEntity = new TUserAccountChangeEntity();
        changeEntity.setChangeId(UUID.randomUUID());
        changeEntity.setUserId(user.getUserId());
        changeEntity.setAccountTrend("10000001");//收入
        changeEntity.setBusinessId(rechargeOrderEntity.getRechargeId());
        changeEntity.setAccountChangeBusinessType("10001001");//充值订单
        changeEntity.setCashAmount(BigDecimal.ZERO);
        changeEntity.setBeforeCashAmount(BigDecimal.ZERO);
        changeEntity.setAfterCashAmount(BigDecimal.ZERO);
        changeEntity.setGoldCoinAmount(BigDecimal.ZERO);
        changeEntity.setBeforeGoldCoinAmount(BigDecimal.ZERO);
        changeEntity.setAfterGoldCoinAmount(BigDecimal.ZERO);
        changeEntity.setRaffleTicket(ticketNum);
        changeEntity.setBeforeRaffleTicket(accountEntity.getRaffleTicket());
        changeEntity.setAfterRaffleTicket(accountEntity.getRaffleTicket() + ticketNum);
        changeEntity.setCreateTime(new Date());
        itUserAccountChangeService.insert(changeEntity);
        //修改账户信息
        accountEntity.setRaffleTicket(ticketNum);
        itUserAccountService.updateByEntity(accountEntity);
        return rechargeId;
    }

    /**
     * 更新所有父级下线人数
     *
     * @param user
     */
    private void updatePid(TUserInfoEntity user) {
        //查询上级实体列表集合
        List<TUserInfoEntity> pidEntities = this.listPidsEntities(user);
        for (TUserInfoEntity e : pidEntities) {
            TUserInfoEntity userInfoEntity = new TUserInfoEntity();
            userInfoEntity.setUserId(e.getUserId());
            int totalSubordinate = e.getTotalSubordinate();
            totalSubordinate++;
            userInfoEntity.setTotalSubordinate(totalSubordinate);
            this.updateById(userInfoEntity);
            //用于下面判断父级大堆
            e.setTotalSubordinate(totalSubordinate);
            //计算并更新父级大堆和第二大堆
            this.judgeSubordinate(e);
        }
    }

    /**
     * 查询上级实体列表集合
     *
     * @param user
     * @return
     */
    private List<TUserInfoEntity> listPidsEntities(TUserInfoEntity user) {
        Wrapper<TUserInfoEntity> wrapper = new EntityWrapper<TUserInfoEntity>()
                .where("1=1")
                .and("user_id in(" + user.getPids() + ")")
                .orderBy("field(user_id," + user.getPids() + ")");
        List<TUserInfoEntity> pidEntitys = this.selectList(wrapper);
        return pidEntitys;
    }

    /**
     * 计算并更新父级大堆
     *
     * @param e
     * @return
     */
    private void judgeSubordinate(TUserInfoEntity e) {
        //查询父级信息
        TUserInfoEntity userInfoEntity = this.selectById(e.getRecommenderUserId());
        //查询不到父级，直接退出（根节点超管没有父级）
        if (null == userInfoEntity) {
            return;
        }
        Integer totalSubordinate = e.getTotalSubordinate() + 1;//分支上的总人数（加上自己本身，也算上级的该分支粉丝）
        boolean isChange = totalSubordinate > userInfoEntity.getMaxSubordinate();
        String maxSubordinateUserId = userInfoEntity.getMaxSubordinateUserId();
        Integer maxSubordinate = userInfoEntity.getMaxSubordinate();
        String secondSubordinateUserId = userInfoEntity.getSecondSubordinateUserId();
        Integer secondSubordinate = userInfoEntity.getSecondSubordinate();
        //先和最大的分支数量进行比较
        if (StringUtils.isBlank(maxSubordinateUserId) || isChange) {
            userInfoEntity.setMaxSubordinateUserId(e.getUserId());
            userInfoEntity.setMaxSubordinate(totalSubordinate);
            //当前最大分支和当前处理用户是一样的，则只进行更新数量操作，不需要再走下面的逻辑了
            if (maxSubordinateUserId.equals(e.getUserId())) {
                this.updateById(userInfoEntity);
                return;
            }
        }
        //最大的分支用户id换人了
        if (StringUtils.isBlank(maxSubordinateUserId) || !maxSubordinateUserId.equals(userInfoEntity.getMaxSubordinateUserId())) {
            isChange = maxSubordinate > userInfoEntity.getSecondSubordinate();
            //换了后的最大分支大于第二分支
            if (null == userInfoEntity.getSecondSubordinateUserId() || isChange) {
                userInfoEntity.setSecondSubordinateUserId(maxSubordinateUserId);
                userInfoEntity.setSecondSubordinate(maxSubordinate);
            }
        } else if (StringUtils.isBlank(secondSubordinateUserId) ||
                (!secondSubordinateUserId.equals(e.getUserId())
                        && totalSubordinate > secondSubordinate))//最大分支没有变化，和第二大分支进行比较
        {
            userInfoEntity.setSecondSubordinate(totalSubordinate);
            userInfoEntity.setSecondSubordinateUserId(e.getUserId());
        }
        this.updateById(userInfoEntity);
    }

    /**
     * 检查角色是否越权
     */
    private void checkRole(TUserInfoEntity user) {
        if (user.getRoleIdList() == null || user.getRoleIdList().size() == 0) {
            return;
        }
        //如果不是超级管理员，则需要判断用户的角色是否自己创建
        if ("1".equals(user.getCreateUserId())) {
            return;
        }
        //查询用户创建的角色列表
        List<String> roleIdList = irUserInfoSysRoleService.queryRoleIdList(user.getCreateUserId());
        //判断是否越权
        if (!roleIdList.containsAll(user.getRoleIdList())) {
            throw new RuntimeException("新增用户所选角色，不是本人创建");
        }
    }

    private static String pidsIsRight(String introducerPids) {
        String[] s = introducerPids.split(",");
        if (s.length >= 150) {
            List<String> list = new ArrayList(Arrays.asList(s));
            list.remove(list.size() - 1);
            return StringUtils.strip(list.toString(), "[]");
        }
        return introducerPids;
    }

    /**
     * 创建用户邀请码
     *
     * @param user
     * @return
     */
    private TUserInfoEntity createInvitation(TUserInfoEntity user) {
        String invitationCode = RedisKeyConfig.invitationCode;
        String invitation = this.generateRandomStr(6);
        String key = invitationCode + invitation;

        if (!RedisLockUtil.tryLock(key, key, RedisKeyConfig.leaseTime)) {
            user = this.createInvitation(user);
        }
        Wrapper<TUserInfoEntity> wrapper = new EntityWrapper<TUserInfoEntity>()
                .where("1=1")
                .eq("invitation", invitation);
        TUserInfoEntity selectEntity = this.selectOne(wrapper);
        if (null != selectEntity) {
            user = this.createInvitation(user);
        }
        user.setInvitation(invitation);//设置邀请码
        return user;
    }

    /**
     * 生成邀请码
     *
     * @param len
     * @return
     */
    private String generateRandomStr(int len) {
        //字符源，可以根据需要删减
        String generateSource = "23456789abcdefghgklmnpqrstuvwxyz";//去掉1和i ，0和o
        String rtnStr = "";
        for (int i = 0; i < len; i++) {
            //循环随机获得当次字符，并移走选出的字符
            String nowStr = String.valueOf(generateSource.charAt((int) Math.floor(Math.random() * generateSource.length())));
            rtnStr += nowStr;
            generateSource = generateSource.replaceAll(nowStr, "");
        }
        return rtnStr.toUpperCase();
    }

    /**
     * @param userInfoEntity
     * @return
     */
    private TUserInfoEntity extendsUserInfo(TUserInfoEntity userInfoEntity) {
        //角色
        if ("1".equals(userInfoEntity.getUserId())) {
            userInfoEntity.setRoleIdList(irUserInfoSysRoleService.queryRoleIdList(null));
        } else {
            userInfoEntity.setRoleIdList(irUserInfoSysRoleService.queryRoleIdList(userInfoEntity.getUserId()));
        }
        //权限标签
        Set<String> set = itSysMenuService.permsByUserId(userInfoEntity.getUserId());
        userInfoEntity.setPermSet(set);
        //用户账户信息
        TUserAccountEntity accountEntity = itUserAccountService.selectById(userInfoEntity.getUserId());
        userInfoEntity.setAccountEntity(accountEntity);
        //用户直推人数
        Wrapper<TUserInfoEntity> wrapper = new EntityWrapper<TUserInfoEntity>()
                .where("1=1")
                .eq("recommender_user_id", TLMap.getUserId());
        //直推数量
        int directCount = this.selectCount(wrapper);
        userInfoEntity.setDirectCount(directCount);
        return userInfoEntity;
    }
}
